# -*- coding: utf-8 -*-
# FileName:     zsimulators2.py
# time:         23/1/12 012 下午 8:46
# Author:       Zhou Hang
# Description:  I don't want to write
import sys
from pathlib import Path

from PyQt5.QtGui import QTextCursor, QIcon
from PyQt5.QtWidgets import QMainWindow, QMessageBox

from common.zerror import MyCoreError
from ProcSims.src.core.paging_linear_translate import LinearTranslateCore
from ProcSims.src.core.malloc import MallocCore
from ProcSims.src.core.paging_multilevel_translate import MultilevelTranslateCore
from ProcSims.src.core.paging_policy import PagePolicyCore
from ProcSims.src.core.relocation import RelocationCore
from ProcSims.src.core.segmentation import SegmentationCore
from ProcSims.src.ui.zsimulators2_ui import Ui_ZSimulators2

malloc_policy_map = {
    '最优匹配': 'BEST',
    '最坏匹配': 'WORST',
    '最先匹配': 'FIRST'
}

malloc_listOrder_map = {
    '地址排序': 'ADDRSORT',
    '大小升序': 'SIZESORT+',
    '大小降序': 'SIZESORT-',
    '插至最前': 'INSERT-FRONT',
    '插至最后': 'INSERT-BACK',
}


class ZSimulators(QMainWindow, Ui_ZSimulators2):
    def __init__(self):
        super(ZSimulators, self).__init__()
        self.pp_addressfile = None
        self.core = None
        self.setupUi(self)
        self.tmp_file = '../output/tmp2.txt'
        self.setWindowIcon(QIcon("../resources/main_icon2.png"))

        self.init_relocation()
        self.init_segmentation()
        self.init_malloc()
        self.init_linear()
        self.init_multilevel()
        self.init_pp()

    # START Common
    def run_core(self, Core, args=None):
        save_stdout = sys.stdout
        sys.stdout = open(self.tmp_file, "w", encoding='utf-8')
        try:
            if args is not None:
                self.core = Core(**args)
            else:
                self.core.show_args()  # 展示参数
        except MyCoreError as e:
            QMessageBox.warning(self, '警告', str(e))
            return
        finally:
            sys.stdout.close()
            sys.stdout = save_stdout

    def put_file_in_gui(self, to_display):
        result = Path(self.tmp_file)
        to_display.setText(result.read_text(encoding='utf-8'))
        to_display.moveCursor(QTextCursor.Start)

    @staticmethod
    def change_table(table, new_value, row_prompt):
        """
        这样封装感觉问题很大，过几天自己都不理解了
        主要功能是根据某个新值增删表格的行数
        :param table: 要修改的表格
        :param new_value: 新的目标行数
        :param row_prompt: 行标
        :return:
        """
        old_process_num = table.get_row_num()
        process_num = new_value
        if process_num > old_process_num:
            table.append_row(row_prompt)
        else:
            table.remove_last_row()
    # END Common

    # START Relocation
    def init_relocation(self):
        self.relocation_asize_comb.addItems(['k', 'm', 'g'])
        self.relocation_physmem_comb.addItems(['k', 'm', 'g'])
        self.relocation_start_btn.clicked.connect(self.relocation_start)

    def relocation_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'asize': f'{self.relocation_asize_sb.text()}{self.relocation_asize_comb.currentText()}',
            'physmem': f'{self.relocation_physmem_sb.text()}{self.relocation_physmem_comb.currentText()}',
            'addresses': self.relocation_addresses_sb.value(),
            'b': self.relocation_b_sb.text(),
            'l': self.relocation_l_sb.text(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(RelocationCore, args)
        self.put_file_in_gui(self.relocation_edit)
    # END Relocation

    # START Segmentation
    def init_segmentation(self):
        self.segmentation_asize_comb.addItems(['k', 'm', 'g'])
        self.segmentation_physmem_comb.addItems(['k', 'm', 'g'])
        self.segmentation_page_num_sb.valueChanged.connect(self.change_segmentation_table)
        self.segmentation_start_btn.clicked.connect(self.segmentation_start)

    def change_segmentation_table(self):
        self.change_table(self.segmentation_addresses_table, self.segmentation_page_num_sb.value(), '第')

    def segmentation_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'addresses': self.segmentation_addresses_table.get_addresses(),
            'asize': f'{self.segmentation_asize_sb.text()}{self.segmentation_asize_comb.currentText()}',
            'physmem': f'{self.segmentation_physmem_sb.text()}{self.segmentation_physmem_comb.currentText()}',
            'numaddrs': self.segmentation_numaddr_sb.value(),
            'b0': self.segmentation_b0_sb.text(),
            'l0': self.segmentation_l0_sb.text(),
            'b1': self.segmentation_b1_sb.text(),
            'l1': self.segmentation_l1_sb.text(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(SegmentationCore, args)
        self.put_file_in_gui(self.segmentation_edit)
    # END Segmentation

    # START Malloc
    def init_malloc(self):
        self.malloc_policy_comb.addItems(malloc_policy_map.keys())
        self.malloc_listOrder_comb.addItems(malloc_listOrder_map.keys())
        self.malloc_numOps_sb.valueChanged.connect(self.change_malloc_table)
        self.malloc_start_btn.clicked.connect(self.malloc_start)

    def change_malloc_table(self):
        self.change_table(self.malloc_allocList_table, self.malloc_numOps_sb.value(), '请求')

    def malloc_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'size': self.malloc_size_sb.value(),
            'baseAddr': self.malloc_baseAddr_sb.value(),
            'headerSize': self.malloc_headerSize_sb.value(),
            'alignment': self.malloc_alignment_sb.value(),
            'policy': malloc_policy_map[self.malloc_policy_comb.currentText()],
            'listOrder': malloc_listOrder_map[self.malloc_listOrder_comb.currentText()],
            'coalesce': self.malloc_coalesce_cb.isChecked(),
            'range': self.malloc_range_sb.value(),
            'percentAlloc': self.malloc_percentAlloc_sb.value(),
            'allocList': self.malloc_allocList_table.get_allocList(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(MallocCore, args)
        self.put_file_in_gui(self.malloc_edit)
    # END Malloc

    # START Linear
    def init_linear(self):
        self.linear_asize_comb.addItems(['k', 'm', 'g'])
        self.linear_physmem_comb.addItems(['k', 'm', 'g'])
        self.linear_pagesize_comb.addItems(['k', 'm', 'g'])

        self.linear_pagenum_sb.valueChanged.connect(self.change_linear_table)
        self.linear_start_btn.clicked.connect(self.start_linear)

    def change_linear_table(self):
        self.change_table(self.linear_addresses_table, self.linear_pagenum_sb.value(), '页')

    def start_linear(self):
        args = {
            'addresses': self.linear_addresses_table.get_addresses(),
            'seed': self.seed_sb.value(),
            'asize': f'{self.linear_asize_sb.text()}{self.linear_asize_comb.currentText()}',
            'physmem': f'{self.linear_physmem_sb.text()}{self.linear_physmem_comb.currentText()}',
            'pagesize': f'{self.linear_pagesize_sb.text()}{self.linear_pagesize_comb.currentText()}',
            'numaddrs': self.linear_numaddrs_sb.value(),
            'used': self.linear_used_sb.value(),
            'verbose': self.printstat_cb.isChecked(),
            'compute': self.compute_cb.isChecked()
        }
        # print(args)
        self.run_core(LinearTranslateCore, args)
        self.put_file_in_gui(self.linear_edit)
    # END Linear

    # START Multilevel
    def init_multilevel(self):
        self.multilevel_start_btn.clicked.connect(self.multilevel_start)

    def multilevel_start(self):
        args = {
            'seed': self.seed_sb.value(),
            'allocated': self.multilevel_allocated_sb.value(),
            'addresses': self.multilevel_addresses_sb.value(),
            'compute': self.compute_cb.isChecked()
        }
        self.run_core(MultilevelTranslateCore, args)
        self.put_file_in_gui(self.multilevel_edit)
    # END Multilevel

    # START Paging Policy
    def init_pp(self):
        self.pp_addressfile = ''
        self.pp_policy_comb.addItems(['FIFO', 'LRU', 'OPT', 'UNOPT', 'RAND', 'CLOCK'])
        self.pp_start_btn.clicked.connect(self.pp_start)
        self.pp_num_addresses_sb.valueChanged.connect(self.change_pp_table)

    def change_pp_table(self):
        self.change_table(self.pp_addresses_table, self.pp_num_addresses_sb.value(), '页')

    def pp_start(self):
        args = {
            'addresses': self.pp_addresses_table.get_addresses(),
            'addressfile': self.pp_addressfile,
            'numaddrs': self.pp_numaddrs_sb.value(),
            'policy': self.pp_policy_comb.currentText(),
            'clockbits': self.pp_clockbits_sb.value(),
            'cachesize': self.pp_cachesize_sb.value(),
            'maxpage': self.pp_maxpage_sb.value(),
            'seed': self.seed_sb.value(),
            'notrace': self.printstat_cb.isChecked(),
            'compute': self.compute_cb.isChecked()
        }
        # print(args)
        self.run_core(PagePolicyCore, args)
        self.put_file_in_gui(self.pp_edit)
    # END Paging Policy


def main():
    pass


if __name__ == "__main__":
    main()
